package cn.yeziji.netty.adapter;

import cn.yeziji.forum.basic.netty.chat.ChatMessage;
import cn.yeziji.forum.basic.netty.user.UserMessage;
import cn.yeziji.forum.common.key.ChatroomCacheKey;
import cn.yeziji.forum.utils.ListsCollect;
import cn.yeziji.forum.utils.RedisUtils;
import cn.yeziji.netty.config.handler.NettyWebsocketHandler;
import cn.yeziji.netty.entity.ChatUserChannelMessage;
import cn.yeziji.forum.basic.netty.chat.ChatroomInfo;
import com.alibaba.fastjson.JSON;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 公共聊天室适配器
 *
 * @author gzkemays
 * @since 2022/11/08 3:42 PM
 */
@Slf4j
public class PublishChatAdapter extends SelectedTypes<ChatMessage>
    implements CommunicationAdapters {
  NettyWebsocketHandler nettyWebsocketHandler = getNettyWebsocketHandler();
  RedisTemplate<String, Object> redisTemplate = getRedisTemplate();
  RedisUtils redisUtils = new RedisUtils(redisTemplate);

  public PublishChatAdapter(Integer type, String text) {
    super(type, text, ChatMessage.class);
    this.data = JSON.parseObject(text, ChatMessage.class);
  }

  @Override
  public void notice(ChannelHandlerContext channelHandlerContext) {
    // 用户进入聊天室
    if (data.getText() == null) {
      List<ChatUserChannelMessage> publicChatList = nettyWebsocketHandler.getPublicChatList();
      ChatUserChannelMessage chatUserChannelMessage =
          new ChatUserChannelMessage(data.getFrom(), channelHandlerContext);
      log.info("{} 进入公共聊天室", data.getFrom().getNickname());
      // 防止异步重复连接
      if (!publicChatList.contains(chatUserChannelMessage)) {
        publicChatList.add(chatUserChannelMessage);
        // 返回公共聊天室当前聊天记录与当前聊天室里的用户
        Object transcriptObj = redisUtils.list0Range(ChatroomCacheKey.PUBLIC_CHAT_KEY);
        // 聊天记录
        List<ChatMessage> transcript = ListsCollect.castList(transcriptObj, ChatMessage.class);
        // 用户列表 -- 这里需要根据用户来获取
        Set<UserMessage> userMessages =
            publicChatList.stream()
                .map(ChatUserChannelMessage::getMessage)
                .collect(Collectors.toSet());
        // 向当前用户发送聊天记录和当前聊天室的用户信息
        writeAndFlush(
            channelHandlerContext,
            ChatroomInfo.publicRoom(transcript, new ArrayList<>(userMessages)));
        // 通知其他用户有新的用户加入
        for (ChatUserChannelMessage userChannelMessage : publicChatList) {
          ChannelHandlerContext context = userChannelMessage.getContext();
          if (context != channelHandlerContext) {
            writeAndFlush(context, data);
          }
        }
      }
    }
  }

  @Override
  public Object dispose(ChannelHandlerContext channelHandlerContext) {
    List<ChatUserChannelMessage> publicChatList = nettyWebsocketHandler.getPublicChatList();
    log.info("{} 向公共聊天室发送消息 --> {}", data.getFrom().getNickname(), data.getText());
    // 保存聊天记录
    if (StringUtils.isNotBlank(data.getText())) {
      // 如果不为空则是发送聊天消息，如果为空，那么就是发送有用户连接的消息
      redisUtils.listFooterPushAll(ChatroomCacheKey.PUBLIC_CHAT_KEY, data);
      redisUtils.setExpire(ChatroomCacheKey.PUBLIC_CHAT_KEY, 1, TimeUnit.DAYS);
      // 遍历连接进行群发
      for (ChatUserChannelMessage chatUserChannelMessage : publicChatList) {
        ChannelHandlerContext connectChannel = chatUserChannelMessage.getContext();
        if (connectChannel == channelHandlerContext) continue;
        writeAndFlush(connectChannel, data);
      }
    }
    return data;
  }
}
